# coding: utf-8
import datetime

from favshop.models import *
from favshop.constant import *
from favshop.utils import *
from favshop.ali import *
from favshop.BeautifulSoup import *
from django.http import HttpResponse
from google.appengine.ext import db
from google.appengine.api import memcache
from google.appengine.api import urlfetch

logging.getLogger().setLevel(logging.INFO)

#-------------------------------------------------------------------------------
# Fetch items information 
#-------------------------------------------------------------------------------

# schedule task keys from http://schedulerservice.appspot.com
# echo crontasks should return keys 
# current, we have 9 cron tasks. 
TASK_KEY_TABLE = ['ulu2dvxqnxeasn9oi2m6osu1swyf1d0d',
    'skqng7h104gnyaw8os1s2340lr4i9ms3',
    '69gcmvfewcxlxt4osznesf6rmipsd36u',
    'atf5vfv846attphvnizjr9z5zkm3b3fa',
    'wqlpfw41dd4pnmts8l3ed8khit3ggraq',
    'bpg3ffv4i6g9j3oa7i88z296olxe3msx',
    'gdkkhx1aj04ywmgycl3x733evwc7anuv',
    'lyjhhvcoi904gdk3jlkdioww02g1l7f7',
    'mj05qrgxj3qwcog2d1bxfapjkbmpcugi',
]

def crontasks(request, index):
    logging.info('crontask-'+index+': '+\
        datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
    try:
        start_timestamp = datetime.datetime.now()
        ret_str = TASK_KEY_TABLE[int(index)-1]
        # start cron task
        # your code goes here...
        favshop_spider()
        # end cron task
        end_timestamp = datetime.datetime.now()
        logging.info('crontask-%s: %s', index, str(end_timestamp-start_timestamp))
    except IndexError:
        logging.warning('convert index from string to integer error.')
        ret_str = ''
    return HttpResponse(ret_str)

def favshop_spider():
    shop_nick, page_number = get_current_updating_shop()
    if shop_nick != '':
        logging.info('updating %s, page %d @%s',
            shop_nick, page_number, str(datetime.datetime.now()))            
        # save updating event to DS
        update_event = SubUpdateLog(nick=shop_nick, 
            log_msg='page '+str(page_number))

        update_event.log_status = update_goods(shop_nick, page_number)
        update_event.put()
    else:
        logging.info('currently, there is no shop need to update')
    return

def get_current_updating_shop():
    '''
    Search information from ShopUpdateInfo, find the current updating shop nick,
    if there is no shop need to update, then return None

    Return current updating shop.  (nick, page_number)
    '''
    entity = getcurrentupdating()
    if entity.nick == '':
        # currently, there is no updating shop
        # get one from SubcriptionInfo
        query = SubscriptionInfo.all().order('last_update_time')
        record_set = query.fetch(1)
        if 0 == len(record_set):
            return ('', 0)
        else:
            record = record_set[0]
            timedelta = datetime.timedelta(minutes=SUBSCRIPTION_UPDATE_INTERVAL)
            if timedelta < (datetime.datetime.now() - record.last_update_time):
                entity.nick = record.nick
                entity.page_number = 2
                entity.put()
                return (entity.nick, 1) # start to update from page 1
            else:
                return ('', 0)
    else:
        entity.page_number += 1
        entity.put()
        return (entity.nick, entity.page_number-1)

def update_goods(nick, page_number):
    '''
    functionality:
    fetch items inforamtion from SIP and save to DS
    '''
    ret_status = False
    
    def trans_current_updating_finish():
        cu_info = getcurrentupdating()
        
        # update SubscriptionInfo
        sub_info = SubscriptionInfo.get_by_key_name(
            MODEL_KEY_PREFIX+cu_info.nick, 
            parent=cu_info)
        if sub_info is not None:
            sub_info.last_update_time = datetime.datetime.now()
            sub_info.put()   
        
        # empty current updating info
        cu_info.nick = ''
        cu_info.page_number = 0
        cu_info.put()
        return
    
    # fetch items data from SIP, then diff and save 
    fetch_obj = taobao_items_get(nicks=nick.encode('utf-8'),
        page_no=str(page_number), page_size=str(ITEMS_GET_PAGE_SIZE),
        fields='iid,title,nick,type,cid,pic_path,delist_time,price,post_fee'
    )
#    logging.info(str(fetch_obj))
    if None == fetch_obj:
        # fetch nothing
        pass
    elif {} == fetch_obj['rsp']:
        # fetch out of bound, current subscription update finished
        # update SubscriptionInfo and CurrentUpdatingInfo
        try:
            db.run_in_transaction(trans_current_updating_finish)
            ret_status = True
        except db.TransactionFailedError:
            logging.warning('trans_current_updating_finish execute failed')
    else:
        for item in fetch_obj['rsp']['items']:
            goods_entity = GoodsInfo.get_by_key_name(MODEL_KEY_PREFIX+item['iid'])
            if goods_entity is None:
                # update event, new goods
#                logging.info(simplejson.dumps(item, indent=2))
                ce_entity = ChangeEvent(summary=u'新货上架',
                    title=item['title'], 
                    content=u'<h3>%s</h3>' % (item['title']),
                    nick=item['nick'])
                
                goods_entity = GoodsInfo(key_name=MODEL_KEY_PREFIX+item['iid'])
                goods_entity.iid = item['iid']
                goods_entity.title = item['title']
                goods_entity.nick = item['nick']
                goods_entity.type = item['type']
                goods_entity.cid = item['cid']
                goods_entity.pic_path = item['pic_path']
                goods_entity.delist_time = str2datetime(item['delist_time'])
                goods_entity.price = float(item['price'])
                goods_entity.post_fee = float(item['post_fee'])
                goods_entity.put()
                
                ce_entity.goods_info = goods_entity
                ce_entity.put()
            else:
                b_changed = False
                item['price'] = float(item['price'])
                if goods_entity.price != item['price']:
                    # update event, price changed 
                    ce_entity = ChangeEvent(summary=u'价格变更',
                        title=item['title'], 
                        content=u'<h3>最新报价：<span class="title_new">%f</span></h3><br /><h3>之前报价：<span class="title_old">%f</span></h3>' % (item['price'], goods_entity.price),
                        nick=item['nick'],
                        goods_info=goods_entity)
                    ce_entity.put()                    
                    
                    goods_entity.price = item['price']
                    b_changed = True
                
                if goods_entity.title != item['title']:
                    # update event, price changed
                    ce_entity = ChangeEvent(summary=u'标题更新',
                        title=item['title'],
                        content=u'<h3>最新标题：<span class="title_new">%s</span></h3><br /><h3>之前标题：<span class="title_old">%s</span></h3>' % (item['title'], goods_entity.title),
                        nick = item['nick'],
                        goods_info=goods_entity)
                    ce_entity.put()
                    
                    goods_entity.title = item['title']
                    b_changed = True
                    
                if b_changed:
                    goods_entity.put()
#        logging.info(simplejson.dumps(fetch_obj['rsp'], indent=2))
        # check whether subscription update finish
        total_result = fetch_obj['rsp']['totalResults']
        if page_number*ITEMS_GET_PAGE_SIZE >= int(total_result):
            # current subscription update finished
            try:
                db.run_in_transaction(trans_current_updating_finish)
                ret_status = True
            except db.TransactionFailedError:
                logging.warning('trans_current_updating_finish execute failed')
        else:
            ret_status = True

    return ret_status

#-------------------------------------------------------------------------------
# Fetch items information - END
#-------------------------------------------------------------------------------

#-------------------------------------------------------------------------------
# Fetch web src of each shop
# http://store.taobao.com/shop/view_shop.htm?shop_nick=XXXX
#-------------------------------------------------------------------------------
FETCHSHOP_TASK_KEY_TABLE = [
    'a5arbw2fgc3wg7njjricrt2l4x4sfgt9',
]

def crontask_fetchshop(request, index):
    try:
        ret_str = FETCHSHOP_TASK_KEY_TABLE[int(index)-1]
        fetchshop_spider()
    except IndexError:
        logging.warning()
        ret_str = ''
    return HttpResponse(ret_str)

def fetchshop_spider():
    shop_nick = fetchshop_get_current()
    if shop_nick != '':
        logging.info('updating %s, wangpu and recommendation', shop_nick)
        update_event = SubUpdateLog(nick=shop_nick,
            log_msg='update wangpu and recommendation')
        update_event.log_status = update_wangpu_and_recommendation(shop_nick)
        update_event.put()
    else:
        logging.info('currently, there is no shop need to update wangpu and recommendation.')
    return
    
def fetchshop_get_current():
    '''
    Search SubscriptionInfo and return the next shop nick which need to update
    wangpu and recommendation.
    '''
    query = SubscriptionInfo.all().order('fetchsop_update_time')
    record_set = query.fetch(1)
    if 0 == len(record_set):
        return ''
    else:
        record = record_set[0]
        timedelta = datetime.timedelta(minutes=SUBSCRIPTION_FETCHSHOP_INTERVAL)
        if timedelta < (datetime.datetime.now() - record.fetchsop_update_time):
            return record.nick
        else:
            return ''
    
def update_wangpu_and_recommendation(nick):
    url = FETCH_SHOP_URL_PREFIX+nick.encode('gb2312')
    ret_status = False
    try:
        result = urlfetch.fetch(url)
        if result.status_code==200:
#            logging.info(result.content)
            sub_info = SubscriptionInfo.get_by_key_name(
                MODEL_KEY_PREFIX+nick, parent=getcurrentupdating())

            # <div class='shop-hot'>
            strainer_shoprecommend = SoupStrainer('div', {'class':'shop-recommend'})
            li = [tag for tag in BeautifulSoup(result.content, 
                parseOnlyThese=strainer_shoprecommend, fromEncoding='GBK')]
            if len(li) == 1:
                if sub_info.recommendation != unicode(li[0].find('ul', {'class':'shop-list'})):
                    sub_info.recommendation = unicode(li[0].find('ul', {'class':'shop-list'}))
                    ce_entity = ChangeEvent(summary=u'推荐更新',
                        title=nick+u'更新了店铺的推荐商品',
                        content=sub_info.recommendation, nick=nick)
                    ce_entity.put()
                    
            # <div class='shop-custom'>
            strainer_colmain = SoupStrainer('div', {'class':'main-wrap'})
            li = [tag for tag in BeautifulSoup(result.content,
                parseOnlyThese=strainer_colmain, fromEncoding='GBK')]
            if len(li) == 1:
                if sub_info.wangpu != unicode(li[0].div.div) and \
                    li[0].div.div['class'] == 'shop-custom':
                    sub_info.wangpu = unicode(li[0].div.div)
                    ce_entity = ChangeEvent(summary=u'公告更新',
                        title=nick+u'更新了店铺的公告栏',
                        content=sub_info.wangpu, nick=nick)
                    ce_entity.put()
                
            # update SubscriptionInfo.fetchshop_update_time
            sub_info.fetchsop_update_time = datetime.datetime.now()
            sub_info.put()
            ret_status = True
        else:
            logging.warning('urlfetch error. status: %d\n%s' % (
                result.status_code, url))
    except urlfetch.InvalidURLError:
        logging.warning('urlfetch InvalidURLError %s', url)
    except urlfetch.DownloadError:
        logging.warning('urlfetch DownloadError %s', url)
    return ret_status

#-------------------------------------------------------------------------------
# Fetch web src of each shop - END
# http://store.taobao.com/shop/view_shop.htm?shop_nick=XXXX
#-------------------------------------------------------------------------------

